# Pythonのイテレータ(iterator)迭代器とジェネレータ(generator)生成器についてまとめてみます。
#
# イテレータ: 要素を反復して取り出すことのできるインタフェース
# ジェネレータ: イテレータの一種であり、1要素を取り出そうとする度に処理を行い、要素をジェネレートするタイプのもの。Pythonではyield文を使った実装を指すことが多いと思われる
# Python組み込みのコレクション(list, tuple, set, dictなど)はどれもイテレーション可能ですが、
# 組み込みのコレクションを使った繰り返し処理ではあらかじめコレクションに値を入れておく必要があるため、以下のようなケースではイテレータやジェネレータを自分で実装したいというケースがあると思います。
#
# 無限に繰り返すイテレーション
# 要素すべてをあらかじめ計算しておく/取得してくるのが計算コスト/処理時間/メモリ使用量などの面で大変
# クラスによるイテレータの実装
# あるオブジェクトをforのinなどのイテレータを期待するコンテクストに置くと、まずオブジェクトの__iter__()メソッドが呼ばれ、イテレータ実装を返すことが求められます。
# この返り値で得られたオブジェクトは__next__()というメソッドが呼ばれます。__next__()はStopIteration例外が出るまで呼ばれます。
#
# 普通にlistとかわりませんが、インスタンス生成時に与えられた数字のリストを順番に返す実装の例です。


# 看着太累了 自己写个中文版吧...我真卑微...
# 迭代器从第一个元素开始访问,直到所有元素被访问完 迭代器只能前进 不能后退
# 迭代器有两个基本的方法：iter() 和 next(),且字符串，列表或元组对象都可用于创建迭代器，迭代器对象可以使用常规 for 语句进行遍历，也可以使用 next() 函数来遍历。
str1 = 'python3'
iter1 = iter(str1)
for x in iter1:
    print(x, end=' ')

# next()迭代器完成会引发StopIteration异常
# for循坏是自带异常处理的 用while的话 记得except一下
while True:
    try:
        print(next(iter1))
    except StopIteration:
        break




# class MyIterator(object):
#     def __init__(self, *numbers):
#         self._numbers = numbers
#         self._i = 0
#     def __iter__(self):
#         # __next__()はselfが実装してるのでそのままselfを返す
#         return self
#     def __next__(self):  # Python2だと next(self) で定義
#         if self._i == len(self._numbers):
#             raise StopIteration()
#         value = self._numbers[self._i]
#         self._i += 1
#         return value
#
# my_iterator = MyIterator(10, 20, 30)
# for num in my_iterator:
#     print('hello %d' % num)


class MyNumbers:
    def __iter__(self):
        self.a = 1
        return self

    def __next__(self):
        x = self.a
        self.a += 1
        return x


myclass = MyNumbers()
myiter = iter(myclass)

print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))


# 反向迭代
list1 = [1, 2, 3, 4, 5]
for num1 in reversed(list1):
    print(num1, end=' ')

# 生成器
# 受到内存限制，列表容量有限的 如果列表元素可以按照某种算法推算出来，那我们希望在循环的过程中不断推算出后续的元素
# 这种一边循环一边计算的机制，称为生成器：generator
# 生成器是一个返回迭代器的函数，只能用于迭代操作 生成器本质也是一个迭代器 但是只能对其迭代一次
# 生成器运行中，每次遇到 yield 时函数会暂停并保存当前所有的运行信息，返回 yield 的值
# 并在下一次执行 next()方法时从当前位置继续运行
# 把一个列表生成式的 [] 改成 () 即可创建一个生成器
gen = (x * x for x in range(10))
print(gen)

for num in gen:
    print(num)

# 要注意 创建 List 和 generator 写法的区别仅在于最外层的 [] 和 ()
# 但是生成器并不真正创建数字列表， 而是返回一个生成器，这个生成器在每次计算出一个条目后，把这个条目 yield 出来
# 从本质上来说 生成器和函数的执行流程不一样 函数是顺序执行，遇到 return 语句或者最后一行语句就返回
# 而变成 generator 的函数，在每次调用 next() 的时候执行，遇到 yield语句返回，再次执行时从上次返回的 yield 语句处继续执行



